package com.groupbuying.redpacket.service.impl;

import com.groupbuying.redpacket.constants.RedPacketListEnumConstants;
import com.groupbuying.redpacket.dao.RedPacketRuleDao;
import com.groupbuying.redpacket.domain.ActivityThemeDO;
import com.groupbuying.redpacket.domain.RedPacketListDO;
import com.groupbuying.redpacket.domain.RedPacketRuleDO;
import com.groupbuying.redpacket.domain.RedPacketTaskDO;
import com.groupbuying.redpacket.service.ActivityThemeService;
import com.groupbuying.redpacket.service.GenerateRedPacketService;
import com.groupbuying.redpacket.service.RedPacketListService;
import com.groupbuying.redpacket.service.RedPacketTaskService;
import com.groupbuying.redpacket.utils.apiresult.ApiResult;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @ClassName GenerateRedPackageServiceImpl
 * @Description: TODO   生成红包实现类
 * @Author srlg3
 * @Date 2019/11/12
 * @Version V1.0
 **/
@Service
public class GenerateRedPacketServiceImpl implements GenerateRedPacketService {

    Logger logger = LoggerFactory.getLogger(GenerateRedPacketServiceImpl.class);

    @Autowired
    private RedPacketRuleDao redPacketRuleDao;

    @Autowired
    private RedPacketListService redPacketListService;

    @Autowired
    private RedPacketTaskService redPacketTaskService;

    @Autowired
    private ActivityThemeService activityThemeService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApiResult GenerateRedPackage(String taskId) {

        //1. 判断
        if (StringUtils.isEmpty(taskId)) {
            logger.error("错误提示：taskId不能为空");
            ApiResult.failure("访问有误");
        }

        StringBuilder build = new StringBuilder();
        build.append("生成红包服务层,taskId:").append(taskId);

        //2. 获取任务表
        RedPacketTaskDO taskDO = redPacketTaskService.get(Long.parseLong(taskId));
        //3. 获取规则
        List<RedPacketRuleDO> rules = redPacketRuleDao.ruleByTaskId(taskId);
        // 获取活动信息
        ActivityThemeDO activityThemeDO = activityThemeService.get(Long.valueOf(taskDO.getAppFlag()));

        //活动规则id
        String activityTheme = activityThemeDO.getId().toString();

        //创建保存对象容器
        List<RedPacketListDO> redPacketListDOS = new ArrayList<>();

        //4.任务信息与规则表是否有效
        for (RedPacketRuleDO rule : rules) {

            //红包总金额
            BigDecimal totalAmt = rule.getTotalAmount();

            //红包总数量
            int totalCount = rule.getTotalCount();

            //金额上限
            BigDecimal amtUp = rule.getMaxAmount();

            //金额下限
            BigDecimal amtDown = rule.getMinAmount();

            build.append(",红包金额:").append(totalAmt).append(",红包总数量:").append(totalCount)
                    .append(",上限:").append(amtUp).append(",下限:").append(amtDown).append("规则id:").append(rule.getId());


            //获取随机数集合
            List<BigDecimal> amtList = null;

            int times = 0;
            while (amtList == null) {

                //重试五次不可以退出
                if (times == 30) {
                    throw new RuntimeException("无法生成红包");
                }

                amtList = productRedPacket(totalAmt, totalCount, amtDown, amtUp);

                System.out.println("当前次数" + times++);
            }
            //组装红包类
            for (int i = 0; i < amtList.size(); i++) {
                RedPacketListDO red = createRedPackageList(taskId, taskDO, rule, amtList.get(i), activityTheme);
                //添加到红包容器中
                redPacketListDOS.add(red);
            }

        }

        //6. 放入数据库当中
        try {
            redPacketListService.batchInsert(redPacketListDOS);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("{},错误提示:红包保存数据库失败", build);
        }

        return ApiResult.success();
    }

    /**
     * @param taskId   任务id
     * @param taskDO   任务信息
     * @param rule     规则信息
     * @param amt      红包金额
     * @param platFrom 活动类型
     * @MethodName: createRedPackageList
     * @Description: TODO   创建红包实体类
     * @Return: com.groupbuying.redpacket.domain.RedPacketListDO
     * @Author: srlg3
     * @Date: 2019/11/22
     */
    private RedPacketListDO createRedPackageList(String taskId, RedPacketTaskDO taskDO,
                                                 RedPacketRuleDO rule, BigDecimal amt, String platFrom) {
        RedPacketListDO red = new RedPacketListDO();

        red.setPlatFrom(platFrom);
        red.setRedPacketAmount(amt);
        red.setRound(taskDO.getRound());
        red.setTaskId(taskId);
        red.setTheme(taskDO.getTheme());
        red.setRuleId(rule.getId().toString());
        red.setType(rule.getName());
        red.setUpdateTime(new Date());
        red.setCreateTime(new Date());
        red.setIsDelete(RedPacketListEnumConstants.ENUM_ISDELETE_UNDEL);
        red.setRedPacketLevel(rule.getRedPacketLevel());
        return red;
    }

    public static void main(String[] args) {
        BigDecimal min = new BigDecimal(60);
        BigDecimal max = new BigDecimal(100);
        BigDecimal totalAmount = new BigDecimal("2000");
        Integer count = 30;

        List<BigDecimal> result = productRedPacket(totalAmount, count, min, max);
        int times = 0;
        while (result == null) {
            System.out.println("当前次数" + times++);
            result = productRedPacket(totalAmount, count, min, max);
        }
        System.out.println("最后结果" + result);
        BigDecimal total = new BigDecimal("0");
        for (BigDecimal red : result) {
            total = total.add(red);
        }
        System.out.println("合计总金额：" + total + "总个数：" + result.size());
//        for (int i=0;i<10000;i++){
//            BigDecimal cur = (new BigDecimal(new Random().nextDouble())
//                    .multiply(new BigDecimal(1.001))) .setScale(3,RoundingMode.HALF_DOWN);
//            if (cur.compareTo(new BigDecimal(1)) != -1){
//                System.out.println(cur);
//            }
//
//
//        }

    }


    /**
     * @param totalAmount 总金额
     * @param totalCount  总数量
     * @param miniAmount  金额下限
     * @param maxAmount   金额上限
     * @MethodName: productRedPacket
     * @Description: TODO   随机生成红包金额
     * @Return: java.util.List<java.math.BigDecimal>
     * @Author: srlg3
     * @Date: 2019/12/2
     */

    public static List<BigDecimal> productRedPacket(BigDecimal totalAmount, Integer totalCount, BigDecimal miniAmount, BigDecimal maxAmount) {
        List<BigDecimal> redPackets = new ArrayList<BigDecimal>();
        ;
        //总平均值
        BigDecimal totalAvgAmount = totalAmount.divide(new BigDecimal(totalCount), 2, RoundingMode.HALF_DOWN);
        //当前总金额
        BigDecimal curTotalAmount = totalAmount;
        //当前红包个数
        Integer curTotalCount = totalCount;
        BigDecimal redPacket = new BigDecimal("0");
        while (curTotalCount > 1) {
            //当前平均值
            BigDecimal curTotalAvgAmount = curTotalAmount.divide(new BigDecimal(curTotalCount), 2, RoundingMode.HALF_UP);
            //整体平均值大于当前平均值
            if (totalAvgAmount.compareTo(curTotalAvgAmount) != -1 && curTotalAvgAmount.compareTo(miniAmount) != -1) {

                redPacket = (new BigDecimal(new Random().nextDouble())
                        .multiply(new BigDecimal(1.001)).setScale(3, RoundingMode.DOWN))
                        .multiply(curTotalAvgAmount.subtract(miniAmount))
                        .add(miniAmount).setScale(2, RoundingMode.DOWN);
                redPackets.add(redPacket);
                curTotalAmount = curTotalAmount.subtract(redPacket);
//                System.out.println("当前min随机金额："+redPacket+"，红包个数:"+curTotalCount+"当前红包余额"+curTotalAmount);
                curTotalCount = curTotalCount - 1;
            } else if (totalAvgAmount.compareTo(curTotalAvgAmount) == -1 && curTotalAvgAmount.compareTo(maxAmount) != 1) {

                redPacket = (new BigDecimal(new Random().nextDouble())
                        .multiply(new BigDecimal(1.001)).setScale(3, RoundingMode.DOWN))
                        .multiply(maxAmount.subtract(curTotalAvgAmount))
                        .add(curTotalAvgAmount).setScale(2, RoundingMode.DOWN);
                redPackets.add(redPacket);
                curTotalAmount = curTotalAmount.subtract(redPacket);
//                System.out.println("当前max随机金额："+redPacket+"，红包个数:"+curTotalCount+"当前红包余额"+curTotalAmount);
                curTotalCount = curTotalCount - 1;
            } else {
                System.out.println("不符合随机金额的限制，退出");
                return null;
            }
        }
        BigDecimal last = curTotalAmount;
        if (last.compareTo(miniAmount) == -1 || last.compareTo(maxAmount) == 1) {
            System.out.println("不符合随机金额的限制，退出");
            return null;
        }
        System.out.println("最后一个红包金额：" + last);
        redPackets.add(last);

        return redPackets;

    }
}
